import pandas as pd
import json
import os
from datetime import datetime
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

class PortfolioManager:
    """持仓管理类，用于跟踪和管理股票持仓"""
    
    def __init__(self, portfolio_file="portfolio.json"):
        """初始化持仓管理器
        
        Args:
            portfolio_file: 持仓数据文件路径
        """
        self.portfolio_file = portfolio_file
        self.logger = logging.getLogger('PortfolioManager')
        self.portfolio = self._load_portfolio()
        
    def _load_portfolio(self):
        """从文件加载持仓数据"""
        if os.path.exists(self.portfolio_file):
            try:
                with open(self.portfolio_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                self.logger.info(f"成功加载持仓数据，共{len(data.get('holdings', []))}只股票")
                return data
            except Exception as e:
                self.logger.error(f"加载持仓数据出错: {str(e)}")
                return {"holdings": [], "transactions": []}
        else:
            self.logger.info("持仓数据文件不存在，创建新的持仓数据")
            return {"holdings": [], "transactions": []}
    
    def _save_portfolio(self):
        """保存持仓数据到文件"""
        try:
            with open(self.portfolio_file, 'w', encoding='utf-8') as f:
                json.dump(self.portfolio, f, ensure_ascii=False, indent=2)
            self.logger.info("持仓数据已保存")
            return True
        except Exception as e:
            self.logger.error(f"保存持仓数据出错: {str(e)}")
            return False
    
    def add_position(self, symbol, name, price, shares, date=None, strategy="价值投资", 
                     stop_loss=None, take_profit=None, notes=None):
        """添加新持仓
        
        Args:
            symbol: 股票代码
            name: 股票名称
            price: 买入价格
            shares: 买入股数
            date: 买入日期，默认为当前日期
            strategy: 投资策略
            stop_loss: 止损价格
            take_profit: 止盈价格
            notes: 备注
        
        Returns:
            成功返回True，失败返回False
        """
        if not date:
            date = datetime.now().strftime("%Y-%m-%d")
        
        # 检查是否已有该股票持仓
        for holding in self.portfolio["holdings"]:
            if holding["symbol"] == symbol:
                self.logger.warning(f"已存在股票{symbol}的持仓，请使用update_position更新")
                return False
        
        # 创建新持仓
        new_position = {
            "symbol": symbol,
            "name": name,
            "buy_price": price,
            "current_price": price,
            "shares": shares,
            "buy_date": date,
            "cost": price * shares,
            "market_value": price * shares,
            "profit_loss": 0,
            "profit_loss_percent": 0,
            "strategy": strategy,
            "stop_loss": stop_loss,
            "take_profit": take_profit,
            "notes": notes
        }
        
        # 添加到持仓列表
        self.portfolio["holdings"].append(new_position)
        
        # 记录交易
        transaction = {
            "date": date,
            "symbol": symbol,
            "name": name,
            "type": "买入",
            "price": price,
            "shares": shares,
            "amount": price * shares,
            "strategy": strategy,
            "notes": notes
        }
        self.portfolio["transactions"].append(transaction)
        
        # 保存到文件
        result = self._save_portfolio()
        if result:
            self.logger.info(f"成功添加{symbol}({name})的持仓，{shares}股，价格{price}")
        return result
    
    def update_position(self, symbol, current_price=None, stop_loss=None, take_profit=None, notes=None):
        """更新持仓信息
        
        Args:
            symbol: 股票代码
            current_price: 当前价格
            stop_loss: 止损价格
            take_profit: 止盈价格
            notes: 备注
        
        Returns:
            成功返回True，失败返回False
        """
        # 查找持仓
        found = False
        for holding in self.portfolio["holdings"]:
            if holding["symbol"] == symbol:
                found = True
                # 更新价格和市值
                if current_price is not None:
                    holding["current_price"] = current_price
                    holding["market_value"] = current_price * holding["shares"]
                    holding["profit_loss"] = holding["market_value"] - holding["cost"]
                    if holding["cost"] > 0:
                        holding["profit_loss_percent"] = (holding["profit_loss"] / holding["cost"]) * 100
                
                # 更新止损止盈价格
                if stop_loss is not None:
                    holding["stop_loss"] = stop_loss
                if take_profit is not None:
                    holding["take_profit"] = take_profit
                
                # 更新备注
                if notes is not None:
                    holding["notes"] = notes
                
                break
        
        if not found:
            self.logger.warning(f"未找到股票{symbol}的持仓")
            return False
        
        # 保存到文件
        result = self._save_portfolio()
        if result:
            self.logger.info(f"成功更新{symbol}的持仓信息")
        return result
    
    def close_position(self, symbol, price, date=None, notes=None):
        """平仓（卖出）
        
        Args:
            symbol: 股票代码
            price: 卖出价格
            date: 卖出日期，默认为当前日期
            notes: 备注
        
        Returns:
            成功返回True，失败返回False
        """
        if not date:
            date = datetime.now().strftime("%Y-%m-%d")
        
        # 查找持仓
        found = False
        position_index = -1
        for i, holding in enumerate(self.portfolio["holdings"]):
            if holding["symbol"] == symbol:
                found = True
                position_index = i
                
                # 记录交易
                transaction = {
                    "date": date,
                    "symbol": symbol,
                    "name": holding["name"],
                    "type": "卖出",
                    "price": price,
                    "shares": holding["shares"],
                    "amount": price * holding["shares"],
                    "profit_loss": (price - holding["buy_price"]) * holding["shares"],
                    "profit_loss_percent": ((price - holding["buy_price"]) / holding["buy_price"]) * 100 if holding["buy_price"] > 0 else 0,
                    "strategy": holding["strategy"],
                    "notes": notes
                }
                self.portfolio["transactions"].append(transaction)
                
                break
        
        if not found:
            self.logger.warning(f"未找到股票{symbol}的持仓")
            return False
        
        # 从持仓列表中移除
        if position_index >= 0:
            self.portfolio["holdings"].pop(position_index)
        
        # 保存到文件
        result = self._save_portfolio()
        if result:
            self.logger.info(f"成功平仓{symbol}，价格{price}")
        return result
    
    def get_holdings(self):
        """获取当前所有持仓
        
        Returns:
            持仓列表的DataFrame
        """
        if not self.portfolio["holdings"]:
            return pd.DataFrame()
        
        return pd.DataFrame(self.portfolio["holdings"])
    
    def get_transactions(self, start_date=None, end_date=None):
        """获取交易记录
        
        Args:
            start_date: 开始日期
            end_date: 结束日期
        
        Returns:
            交易记录的DataFrame
        """
        if not self.portfolio["transactions"]:
            return pd.DataFrame()
        
        df = pd.DataFrame(self.portfolio["transactions"])
        
        # 筛选日期范围
        if start_date:
            df = df[df["date"] >= start_date]
        if end_date:
            df = df[df["date"] <= end_date]
        
        return df
    
    def calculate_alerts(self, quotes_data):
        """计算止盈止损提醒
        
        Args:
            quotes_data: 股票报价数据，包含symbol和price字段的DataFrame
        
        Returns:
            止盈止损提醒列表
        """
        if quotes_data.empty or not self.portfolio["holdings"]:
            return []
        
        alerts = []
        
        # 转换为字典以便快速查找
        quotes_dict = {}
        for _, row in quotes_data.iterrows():
            quotes_dict[row["symbol"]] = row["price"]
        
        # 检查每个持仓
        for holding in self.portfolio["holdings"]:
            symbol = holding["symbol"]
            
            if symbol in quotes_dict:
                current_price = quotes_dict[symbol]
                
                # 更新当前价格
                self.update_position(symbol, current_price=current_price)
                
                # 检查止损提醒
                if holding.get("stop_loss") and current_price <= holding["stop_loss"]:
                    alerts.append({
                        "type": "止损",
                        "symbol": symbol,
                        "name": holding["name"],
                        "current_price": current_price,
                        "threshold_price": holding["stop_loss"],
                        "buy_price": holding["buy_price"],
                        "profit_loss_percent": ((current_price - holding["buy_price"]) / holding["buy_price"]) * 100 if holding["buy_price"] > 0 else 0
                    })
                
                # 检查止盈提醒
                if holding.get("take_profit") and current_price >= holding["take_profit"]:
                    alerts.append({
                        "type": "止盈",
                        "symbol": symbol,
                        "name": holding["name"],
                        "current_price": current_price,
                        "threshold_price": holding["take_profit"],
                        "buy_price": holding["buy_price"],
                        "profit_loss_percent": ((current_price - holding["buy_price"]) / holding["buy_price"]) * 100 if holding["buy_price"] > 0 else 0
                    })
        
        return alerts
    
    def calculate_portfolio_stats(self):
        """计算投资组合统计信息
        
        Returns:
            包含总成本、总市值、总盈亏等信息的字典
        """
        if not self.portfolio["holdings"]:
            return {
                "total_cost": 0,
                "total_market_value": 0,
                "total_profit_loss": 0,
                "total_profit_loss_percent": 0,
                "position_count": 0
            }
        
        total_cost = sum(holding["cost"] for holding in self.portfolio["holdings"])
        total_market_value = sum(holding["market_value"] for holding in self.portfolio["holdings"])
        total_profit_loss = total_market_value - total_cost
        total_profit_loss_percent = (total_profit_loss / total_cost) * 100 if total_cost > 0 else 0
        
        return {
            "total_cost": total_cost,
            "total_market_value": total_market_value,
            "total_profit_loss": total_profit_loss,
            "total_profit_loss_percent": total_profit_loss_percent,
            "position_count": len(self.portfolio["holdings"])
        }
